package cn.iocoder.yudao.module.system.job.cp;

import cn.iocoder.yudao.framework.tenant.core.context.TenantContextHolder;
import cn.iocoder.yudao.module.system.dal.dataobject.dept.DeptDO;
import cn.iocoder.yudao.module.system.dal.dataobject.user.AdminUserDO;
import cn.iocoder.yudao.module.system.dal.mysql.dept.DeptMapper;
import cn.iocoder.yudao.module.system.dal.mysql.user.AdminUserMapper;
import cn.iocoder.yudao.module.system.enums.cp.CpEnum;
import cn.iocoder.yudao.module.system.framework.cp.config.WxCpConfiguration;
import cn.iocoder.yudao.module.system.service.user.AdminUserService;
import com.google.common.collect.Lists;
import lombok.extern.slf4j.Slf4j;
import me.chanjar.weixin.common.error.WxErrorException;
import me.chanjar.weixin.cp.api.WxCpService;
import me.chanjar.weixin.cp.bean.Gender;
import me.chanjar.weixin.cp.bean.WxCpDepart;
import me.chanjar.weixin.cp.bean.WxCpUser;
import org.springframework.scheduling.annotation.Async;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.stream.Collectors;

/**
 * @author pg
 * @project zysx
 * @description 同步服务
 * @date 2024/11/7 18:21:31
 */
@Service
@Slf4j
public class SyncService {
    @Resource
    private DeptMapper deptMapper;

    @Resource
    private PasswordEncoder passwordEncoder;

    @Resource
    private AdminUserMapper userMapper;

    @Resource
    private AdminUserService adminUserService;

    @Async
    public void sync() throws WxErrorException {
        Long tenantId = TenantContextHolder.getTenantId();
        final WxCpService wxCpService = WxCpConfiguration.getCpService(CpEnum.valueOfTenantId(Math.toIntExact(tenantId)).getCorpId(), CpEnum.valueOfTenantId(Math.toIntExact(tenantId)).getAgentId());
        List<WxCpDepart> result = wxCpService.getDepartmentService().list(1L);
        log.info("成功获取部门个数：{}", result.size());
        // 转为以ID为key的Map，考虑tenantId的影响
        Map<Long, WxCpDepart> wxCpDepartMap = result.stream()
                .collect(java.util.stream.Collectors.toMap(
                        wxCpDepart -> wxCpDepart.getId() + (tenantId - 1) * 1000L,
                        wxCpDepart -> wxCpDepart
                ));
        // 一次性查询所有现有部门
        List<DeptDO> sourceDepts = deptMapper.selectListByCp();
        sourceDepts.forEach(deptDO -> {
            // 如果存在则更新
            if (wxCpDepartMap.containsKey(deptDO.getId())) {
                WxCpDepart wxCpDepart = wxCpDepartMap.get(deptDO.getId());
                if (!Objects.equals(deptDO.getName(), wxCpDepart.getName()) || !Objects.equals(deptDO.getParentId(), wxCpDepart.getParentId())) {
                    WxCpDepart wxCp = new WxCpDepart();
                    wxCp.setId(deptDO.getId());
                    wxCp.setName(wxCpDepart.getName());
                    wxCp.setParentId(wxCpDepart.getParentId() + (tenantId - 1) * 1000L);
                    deptMapper.updateInfoById(wxCp);
                }
            } else {
                // 删除
                deptMapper.deleteById(deptDO.getId());
            }
        });

        // 添加新增部门
        wxCpDepartMap.forEach((id, wxCpDepart) -> {
            // 检查现有部门中是否存在该部门
            boolean exists = sourceDepts.stream()
                    .anyMatch(deptDO -> deptDO.getId().equals(id));

            // 如果不存在，则添加新的部门
            if (!exists) {
                DeptDO vo = new DeptDO();
                vo.setSort(Math.toIntExact(wxCpDepart.getOrder()));
                vo.setStatus(0);
                vo.setId(wxCpDepart.getId() + (tenantId - 1) * 1000L);
                vo.setName(wxCpDepart.getName());
                vo.setParentId(wxCpDepart.getParentId() + (tenantId - 1) * 1000L);
                deptMapper.insert(vo);
            }
        });

        syncUser(result, tenantId, wxCpService);
    }

    private void syncUser(List<WxCpDepart> departs, Long tenantId, WxCpService wxCpService) throws WxErrorException {
        log.info("开始同步用户");
        List<AdminUserDO> userDOS = Lists.newArrayList();
        for (WxCpDepart deptDO : departs) {
            List<WxCpUser> result = wxCpService.getUserService().listByDepartment(deptDO.getId(), null, null);
            userDOS.addAll(converList(result, Math.toIntExact(tenantId)));
        }
        userDOS = userDOS.stream().filter(distinctByKey(AdminUserDO::getUsername)).collect(Collectors.toList());
        List<AdminUserDO> oldUsers = userMapper.selectListByCp();
        oldUsers = oldUsers.stream().filter(distinctByKey(AdminUserDO::getUsername)).filter(x -> x.getId() > 2).collect(Collectors.toList());

        // 更新、删除或新增用户
        Map<String, AdminUserDO> newUserMap = userDOS.stream()
                .collect(Collectors.toMap(AdminUserDO::getUsername, user -> user));

        // 更新与删除处理
        for (AdminUserDO oldUser : oldUsers) {
            if (newUserMap.containsKey(oldUser.getUsername())) {
                // 更新用户
                AdminUserDO updatedUser = newUserMap.get(oldUser.getUsername());
                if (Boolean.TRUE.equals(oldUser.getDeleted()) || !Objects.equals(oldUser.getDeptId(), updatedUser.getDeptId())) {
                    updatedUser.setId(oldUser.getId());
                    userMapper.updateUserByCp(updatedUser);
                }
            } else {
                // 删除用户
                if (Boolean.FALSE.equals(oldUser.getDeleted())) {
//                    userMapper.deleteById(oldUser.getId());
                    // 改成更新为无效状态
                    adminUserService.updateUserStatus(oldUser.getId(), 1);
                }
            }
        }

        // 新增用户处理
        processNewUsers(userDOS, oldUsers);

    }

    static <T> Predicate<T> distinctByKey(Function<? super T, ?> keyExtractor) {
        Set<Object> seen = ConcurrentHashMap.newKeySet();
        return t -> seen.add(keyExtractor.apply(t));
    }

    private void processNewUsers(List<AdminUserDO> userDOS, List<AdminUserDO> oldUsers) {
        // 使用 HashSet 存储旧用户的用户名
        Set<String> oldUsernames = new HashSet<>();
        for (AdminUserDO oldUser : oldUsers) {
            if (oldUser.getUsername() != null) {
                oldUsernames.add(oldUser.getUsername());
            }
        }

        List<AdminUserDO> addUsers = new ArrayList<>();
        // 新增用户处理
        for (AdminUserDO newUser : userDOS) {
            if (newUser.getUsername() != null && !oldUsernames.contains(newUser.getUsername())) {
                addUsers.add(newUser);
            }
        }
        userMapper.insertBatch(addUsers);
    }

    private List<AdminUserDO> converList(List<WxCpUser> result, Integer tenantId) {
        List<AdminUserDO> users = Lists.newArrayList();
        result.forEach(
                wxCpUser -> {
                    AdminUserDO adminUserDO = new AdminUserDO();
                    adminUserDO.setMobile(wxCpUser.getMobile());
                    adminUserDO.setUsername(wxCpUser.getUserId().toLowerCase());
                    adminUserDO.setPassword(passwordEncoder.encode("zcsx123"));
                    adminUserDO.setDeptId(wxCpUser.getDepartIds()[0] + (tenantId - 1) * 1000L);
                    adminUserDO.setStatus(0);
                    adminUserDO.setNickname(wxCpUser.getName());
                    adminUserDO.setEmail(wxCpUser.getEmail());
                    adminUserDO.setAvatar(wxCpUser.getAvatar());
                    adminUserDO.setSex(getGen(wxCpUser.getGender()));
                    adminUserDO.setWxUserId(wxCpUser.getUserId());
                    users.add(adminUserDO);
                }
        );
        return users;
    }

    private Integer getGen(Gender gender) {
        if (gender == null) {
            return 3;
        }
        if ("MALE".equals(gender.toString())) {
            return 0;
        } else if ("FEMALE".equals(gender.toString())) {
            return 1;
        }
        return 3;
    }
}
